#include "user_password.h"

#if GKT_USER_PASSWORD_DYNAMIC_ENABLE

uint8_t user_password_get_check_value(
				const uint8_t *units, uint32_t units_size)
{
	uint32_t check_value, i;

	check_value = 0;
	for (i = 0; i < units_size; i++)
		check_value += units[i] * (i + 1);
	while (check_value > 0x0f)
		check_value = (check_value >> 4) ^ (check_value & 0x0f);

	return (uint8_t)check_value;
}

/* 0 <= shift < 0x10 */
void user_password_rotate_left_shift(
				uint8_t *units, uint32_t units_size, 
				uint32_t shift)
{
	uint32_t shift_units_nums, shift_bits, i;
	uint8_t tmp[4];

	if (!shift)
		shift = 0x10;

	shift_units_nums = (shift >> 2) % units_size;
	if (shift_units_nums) {
		for (i = 0; i < shift_units_nums; i++)
			tmp[i] = units[i];
		while (i < units_size) {
			units[i - shift_units_nums] = units[i];
			i++;
		}
		while (shift_units_nums)
			units[--i] = tmp[--shift_units_nums];
	}

	shift_bits = shift & 3;
	if (shift_bits) {
		tmp[0] = units[0] >> (4 - shift_bits);
		units[0] = (units[0] << shift_bits) & 0x0f;
		for (i = 1; i < units_size; i++) {
			units[i - 1] |= units[i] >> (4 - shift_bits);
			units[i] = (units[i] << shift_bits) & 0x0f;
		}
		units[units_size - 1] |= tmp[0];
	}
}

void user_password_rotate_right_shift(
				uint8_t *units, uint32_t units_size, 
				uint32_t shift)
{
	uint32_t shift_units_nums, shift_bits;
	uint32_t i, offset, mask;
	uint8_t tmp[4];

	if (!shift)
		shift = 0x10;

	shift_units_nums = (shift >> 2) % units_size;
	if (shift_units_nums) {
		offset = units_size - shift_units_nums;
		for (i = 0; i < shift_units_nums; i++)
			tmp[i] = units[offset + i];
		while (offset-- > 0)
			units[offset + shift_units_nums] = units[offset];
		while (shift_units_nums--)
			units[shift_units_nums] = tmp[shift_units_nums];
	}

	shift_bits = shift & 3;
	if (shift_bits) {
		mask = (1U << shift_bits) - 1;
		tmp[0] = (units[units_size - 1] & mask) << (4 - shift_bits);
		for (i = units_size - 1; i > 0; i--) {
			units[i] >>= shift_bits;
			units[i] |= (units[i - 1] & mask) << (4 - shift_bits);
		}
		units[0] = tmp[0] | (units[0] >> shift_bits);
	}
}

void user_password_xor(uint8_t *data_units, 
				uint32_t data_units_size, uint8_t xor_value)
{
	uint32_t i;

	if (!xor_value)
		xor_value = 0x0f;
	for (i = 0; i < data_units_size; i++)
		data_units[i] ^= xor_value;
}

#endif

